/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.ior;

import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;

import org.omg.IOP.TAG_INTERNET_IOP;

import org.omg.CORBA_2_3.portable.OutputStream;
import org.omg.CORBA_2_3.portable.InputStream;

import com.sun.corba.se.spi.ior.TaggedComponent;
import com.sun.corba.se.spi.ior.Identifiable;
import com.sun.corba.se.spi.ior.IdentifiableFactoryFinder;
import com.sun.corba.se.spi.ior.WriteContents;

import com.sun.corba.se.spi.orb.ORB;

import com.sun.corba.se.impl.ior.FreezableList;

import com.sun.corba.se.impl.encoding.CDROutputStream;
import com.sun.corba.se.impl.encoding.EncapsOutputStream;
import com.sun.corba.se.impl.encoding.EncapsInputStream;

import sun.corba.EncapsInputStreamFactory;

/**
 * This static utility class contains various utility methods for reading and
 * writing CDR encapsulations.
 *
 * @author Ken Cavanaugh
 */
public class EncapsulationUtility {

  private EncapsulationUtility() {
  }

  /**
   * Read the count from is, then read count Identifiables from
   * is using the factory.  Add each constructed Identifiable to container.
   */
  public static void readIdentifiableSequence(List container,
      IdentifiableFactoryFinder finder, InputStream istr) {
    int count = istr.read_long();
    for (int ctr = 0; ctr < count; ctr++) {
      int id = istr.read_long();
      Identifiable obj = finder.create(id, istr);
      container.add(obj);
    }
  }

  /**
   * Write all Identifiables that we contain to os.  The total
   * length must be written before this method is called.
   */
  public static void writeIdentifiableSequence(List container, OutputStream os) {
    os.write_long(container.size());
    Iterator iter = container.iterator();
    while (iter.hasNext()) {
      Identifiable obj = (Identifiable) (iter.next());
      os.write_long(obj.getId());
      obj.write(os);
    }
  }

  /**
   * Helper method that is used to extract data from an output
   * stream and write the data to another output stream.  Defined
   * as static so that it can be used in another class.
   */
  static public void writeOutputStream(OutputStream dataStream,
      OutputStream os) {
    byte[] data = ((CDROutputStream) dataStream).toByteArray();
    os.write_long(data.length);
    os.write_octet_array(data, 0, data.length);
  }

  /**
   * Helper method to read the octet array from is, deencapsulate it,
   * and return
   * as another InputStream.  This must be called inside the
   * constructor of a derived class to obtain the correct stream
   * for unmarshalling data.
   */
  static public InputStream getEncapsulationStream(InputStream is) {
    byte[] data = readOctets(is);
    EncapsInputStream result = EncapsInputStreamFactory.newEncapsInputStream(is.orb(), data,
        data.length);
    result.consumeEndian();
    return result;
  }

  /**
   * Helper method that reads an octet array from an input stream.
   * Defined as static here so that it can be used in another class.
   */
  static public byte[] readOctets(InputStream is) {
    int len = is.read_ulong();
    byte[] data = new byte[len];
    is.read_octet_array(data, 0, len);
    return data;
  }

  static public void writeEncapsulation(WriteContents obj,
      OutputStream os) {
    EncapsOutputStream out =
        sun.corba.OutputStreamFactory.newEncapsOutputStream((ORB) os.orb());

    out.putEndian();

    obj.writeContents(out);

    writeOutputStream(out, os);
  }
}
